package com.cqdev.washer.api.controller;

import com.cqdev.washer.api.model.InputScript;
import com.cqdev.washer.api.model.ScriptVO;
import com.cqdev.washer.biz.enums.ScriptExecuteResultEnum;
import com.cqdev.washer.biz.model.ProjectBO;
import com.cqdev.washer.biz.model.SqlScriptBO;
import com.cqdev.washer.biz.service.ExecuteService;
import com.cqdev.washer.biz.service.ProjectService;
import com.cqdev.washer.biz.service.ScriptService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author yunfei.li
 *         类描述: TODO
 *         日期： 2018/7/2
 */
@Controller
public class ScriptController {

    private final ProjectService projectService;
    private final ExecuteService executeService;
    private final ScriptService scriptService;

    public ScriptController(ProjectService projectService, ExecuteService executeService, ScriptService scriptService) {
        this.projectService = projectService;

        this.executeService = executeService;
        this.scriptService = scriptService;
    }

    @GetMapping("/project/{id}/script/list")
    public String toEditScript(@PathVariable("id") Long projectId, Model model) {
        ProjectBO projectBO = projectService.getOne(projectId);
        List<SqlScriptBO> sqlScriptBOList = projectBO.getSqlScriptBOList();

        List<ScriptVO> scriptVOList = sqlScriptBOList.stream().map(sqlScriptBO -> new ScriptVO(
                sqlScriptBO.getId(),
                sqlScriptBO.getScript(),
                sqlScriptBO.getName(),
                sqlScriptBO.getDescription(),
                sqlScriptBO.getSn(),
                sqlScriptBO.getLastExecuteTime(),
                sqlScriptBO.getLastExecuteStatus(),
                sqlScriptBO.getExecuteCount(),
                sqlScriptBO.getLastElapsedTime()
        )).collect(Collectors.toList());
        long totalElapsedTime = sqlScriptBOList.stream().mapToLong(SqlScriptBO::getLastElapsedTime).sum();
        DecimalFormat decimalFormat = new DecimalFormat("#,###");

        long failScriptCount = sqlScriptBOList.stream().filter(sqlScriptBO -> {
            if (sqlScriptBO.getLastExecuteStatus() != null) {
                if (ScriptExecuteResultEnum.valueOf(sqlScriptBO.getLastExecuteStatus()) == ScriptExecuteResultEnum.FAIL) {
                    return true;
                }
            }
            return false;
        }).count();

        model.addAttribute("scripts", scriptVOList);
        model.addAttribute("projectId", projectId);
        model.addAttribute("projectName", projectBO.getName());
        model.addAttribute("totalElapsedTime", decimalFormat.format(totalElapsedTime));
        model.addAttribute("failScriptCount", failScriptCount);
        model.addAttribute("scriptCount", sqlScriptBOList.size());
        return "scriptList";
    }

    @GetMapping("/project/{projectId}/script/input")
    public String toCreateScript(@PathVariable("projectId") Long projectId, @RequestParam(value = "scriptId", required = false) Long scriptId, ModelMap model) {
        ProjectBO projectBO = projectService.getOne(projectId);

        if (scriptId != null) {
            Optional<SqlScriptBO> scriptBO = projectBO.getSqlScriptBOList().stream().filter(sqlScriptBO -> sqlScriptBO.equals(scriptId)).findFirst();
            if (scriptBO.isPresent()) {
                model.put("script", scriptBO);
            }
        }
        model.put("projectName", projectBO.getName());
        model.put("projectId", projectId);
        return "inputScript";
    }

    @PostMapping("/project/{projectId}/script/input")
    String inputScript(@PathVariable("projectId") Long projectId, InputScript inputScript) {
        ProjectBO projectBO = projectService.getOne(projectId);

        Optional<SqlScriptBO> optional = projectBO.getSqlScriptBOList().stream().max(Comparator.comparing(SqlScriptBO::getSn));
        if (!optional.isPresent()) {
            throw new RuntimeException("system error");
        }
        SqlScriptBO sqlScriptBO = new SqlScriptBO(
                inputScript.getScript(),
                inputScript.getName(),
                inputScript.getDescription(),
                optional.get().getSn() + 1
        );

        projectBO.setSqlScriptBOList(Collections.singletonList(sqlScriptBO));

        projectService.save(projectBO);
        return "redirect:/project/" + projectId + "/script/list";
    }

    @GetMapping("/project/{projectId}/script/delete/{id}")
    public String deleteScript(@PathVariable("id") Long id, @PathVariable(value = "projectId") Long projectId) {

        scriptService.deleteScript(id);

        return "redirect:/project/" + projectId + "/script/list";
    }

    @GetMapping("/project/{projectId}/script/execute/{id}")
    public String executeScript(@PathVariable("id") Long id, @PathVariable(value = "projectId") Long projectId, RedirectAttributes redirectAttributes) {
        SqlScriptBO scriptOne = projectService.getScriptOne(id);

        if (scriptOne == null) {
            redirectAttributes.addFlashAttribute("message", "script 执行失败!!!!");
        }
        try {
            executeService.exec(projectId, id);
            redirectAttributes.addFlashAttribute("message", "脚本:" + scriptOne.getName() + ",执行成功！");
        } catch (Exception e) {
            redirectAttributes.addFlashAttribute("message", "脚本:" + scriptOne.getName() + ",执行失败！  , error = " + e.getMessage());
        }

        return "redirect:/project/" + projectId + "/script/list";
    }
}
